package com.sunshine.androidjavapractise.socket;

import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.NonNull;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.util.ArrayList;

import static com.sunshine.androidjavapractise.socket.SocketClient.State.Connected;
import static com.sunshine.androidjavapractise.socket.SocketClient.State.Connecting;
import static com.sunshine.androidjavapractise.socket.SocketClient.State.Disconnected;

public class SocketClient {
    // connect state
    private State mState = Disconnected;
    private SocketAddress mSocketAddress;
    private Socket mSocket;
    private ArrayList<SocketClientDelegate> mSocketClientDelegates = new ArrayList<>();
    private SendThread mSendThread = new SendThread();
    private ReceiveThread mReceiveThread = new ReceiveThread();
    private ConnectionThread mConnectionThread = new ConnectionThread();
    private CountDownTimer mCountDownTimer = new CountDownTimer(Long.MAX_VALUE, 1000L) {
        @Override
        public void onTick(long millisUntilFinished) {

        }

        @Override
        public void onFinish() {

        }
    };
    public SocketClient(String ip, String port) {
        mSocketAddress = new SocketAddress(ip, port);
        mSocket = new Socket();
    }

    public void connect() {
        if (!isDisconnected()) {
            return;
        }
        setState(Connecting);
        mConnectionThread.start();
    }

    public void disConnect() {

    }

    public boolean isDisconnected() {
        return mState == Disconnected;
    }

    public enum State {
        Disconnected, Connecting, Connected
    }

    public void setState(State state) {
        mState = state;
    }


    private class ConnectionThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                if (Thread.interrupted()) {
                    return;
                }
                mSocket.connect(mSocketAddress.getInetSocketAddress());
                if (Thread.interrupted()) {
                    return;
                }
                setState(Connected);
                mConnectionThread = null;
                onConnected();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void onConnected() {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            getUiHandler().post(new Runnable() {
                @Override
                public void run() {
                    onConnected();
                }
            });
            return;
        }
        for (SocketClientDelegate socketClientDelegate : mSocketClientDelegates) {
            socketClientDelegate.onConnected(this);
        }
        mSendThread.start();
        mReceiveThread.start();
    }

    private void onDisconnected() {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            getUiHandler().post(new Runnable() {
                @Override
                public void run() {
                    onDisconnected();
                }
            });
            return;
        }
        for (SocketClientDelegate socketClientDelegate : mSocketClientDelegates) {
            socketClientDelegate.onDisconnected(this);
        }
    }

    public SocketClient registerSocketClientDelegate(SocketClientDelegate delegate) {
        if (!mSocketClientDelegates.contains(delegate)) {
            mSocketClientDelegates.add(delegate);
        }
        return this;
    }

    private UIHandler mUiHandler;

    protected UIHandler getUiHandler() {
        if (this.mUiHandler == null) {
            this.mUiHandler = new UIHandler(this);
        }
        return this.mUiHandler;
    }

    private static class UIHandler extends Handler {
        private WeakReference<SocketClient> referenceSocketClient;

        public UIHandler(@NonNull SocketClient referenceSocketClient) {
            super(Looper.getMainLooper());

            this.referenceSocketClient = new WeakReference<SocketClient>(referenceSocketClient);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }

    private class SendThread extends Thread {
        @Override
        public void run() {
            super.run();
        }
    }

    private class ReceiveThread extends Thread {
        @Override
        public void run() {
            super.run();
        }
    }
}
